import logging

from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, GenericViewSet, ReadOnlyModelViewSet, ViewSet
from rest_framework.mixins import *
from rest_framework.permissions import IsAuthenticated
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR, \
    HTTP_403_FORBIDDEN
from fdfs_client.client import get_tracker_conf, Fdfs_client

from config.fastdfs.config import FASTDFS_SERVER_DOMAIN
from .models import *
from .serializers import *
from utils.customPermissions import *
from lms.settings import alipay

# tracker server
tracker_path = get_tracker_conf('config/fastdfs/client.conf')
client = Fdfs_client(tracker_path)

# 导入日志器
logger = logging.getLogger(__name__)


# Create your views here.
# 一级类目
# 增删改查，老师
class ClassificationViewSet(ModelViewSet):
    queryset = Classification.objects.filter(parent=None, is_delete=False)
    serializer_class = ParentClassificationSerializer
    permission_classes = [TeacherPermission]


# 查，登录
class ClassificationStudentViewSet(GenericViewSet, ListModelMixin):
    queryset = Classification.objects.filter(parent=None, is_delete=False)
    serializer_class = ParentClassificationSerializer
    permission_classes = [IsAuthenticated]

    @action(methods=['get'], detail=True)
    def commodity(self, request, pk):
        try:
            classification = Classification.objects.filter(is_delete=False).get(pk=pk)
        except Classification.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        # 判断该类目是一级分类还是子分类
        '''
         # 方法一
        if classification.parent:
            # 子分类下商品
            data = classification.classification2.filter(is_delete=False)
            classification_name = f'{classification.parent.name}-{classification.name}'
        else:
            # 一级类目下商品
            data = classification.classification1.filter(is_delete=False)
            classification_name = classification.name
        '''
        # 方法二
        classification_attr = 'classification1'
        classification_name = classification.name
        if classification.parent:
            classification_attr = 'classification2'
            classification_name = f'{classification.parent.name}-{classification.name}'

        data = getattr(classification, classification_attr).filter(is_delete=False)  # 根据类目级别，获取商品信息

        return Response({'classification': classification_name, 'commodity': CommoditySerializer(data, many=True).data})


# 商品上架，老师权限
class CommodityViewSet(ModelViewSet):
    queryset = Commodity.objects.filter(is_delete=False)
    serializer_class = CommoditySerializer
    permission_classes = [TeacherPermission]

    @action(methods=['post'], detail=True)
    def img(self, request, pk):
        """
        商品图片上传功能
        1.根据pk获取商品对象
        2.获取传入的信息（商品图片文件：request.FILES）
        3.校验（文件数据和格式）
        4.上传到FastDFS
        5.将返回的地址存储到mysql数据库（商品图片表）
        6.返回响应
        :param request:
        :param pk:
        :return:
        """
        # 1.根据pk获取商品对象
        try:
            commodity = self.get_queryset().get(pk=pk)
        except Commodity.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
            # 2.获取传入的信息（商品图片文件：request.FILES）
        files = request.FILES.get('file')
        # 3.校验（文件数据和格式）
        if not files or files.content_type not in ('image/jpeg', 'image/png', 'image/gif'):
            return Response(status=HTTP_400_BAD_REQUEST)
        # 4.上传到FastDFS
        try:
            image_ext_name = files.name.split('.')[-1]
        except Exception as e:
            image_ext_name = 'png'

        try:
            upload_res = client.upload_by_buffer(files.read(), file_ext_name=image_ext_name)
        except Exception as e:
            logger.error(f'图片上传出现错误：{e}')
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            if upload_res.get('Status') != 'Upload successed.':
                return Response({'msg': '图片上传失败，请稍后重试'}, status=HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                # 5.将返回的地址存储到mysql数据库（商品图片表）
                image_url = FASTDFS_SERVER_DOMAIN + upload_res.get('Remote file_id').decode()
                CommodityImg.objects.create(src=image_url, commodity=commodity)
                # 6.返回响应
                return Response({'data': image_url})


# 商品展示，登录权限
class CommodityStudentViewSet(GenericViewSet, RetrieveModelMixin):  # 商品详情===查单一
    queryset = Commodity.objects.filter(is_delete=False, status=1)
    serializer_class = CommoditySerializer
    permission_classes = [IsAuthenticated]

    @action(methods=['get'], detail=False)
    def optimization(self, request):
        """
        商城优选书籍展示
        :param request:
        :return:
        """
        queryset = self.get_queryset().order_by('-comments').order_by('-c_time')
        if len(queryset) > 5:
            queryset = queryset[:5]
        return Response(self.get_serializer(queryset, many=True).data)


# 购物车
class ShoppingCartViewSet(ModelViewSet):
    # 查询集，当前用户查看自己的购物车
    def get_queryset(self):
        return self.request.user.shoppingcart_set.all()

    serializer_class = ShoppingCartSerializer
    permission_classes = [IsAuthenticated]

    @auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)


# 订单
class OrderViewSet(ReadOnlyModelViewSet, CreateModelMixin):  # 订单不支持修改功能
    def get_queryset(self):
        return self.request.user.order_set

    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]


# 支付功能
class PaymentViewSet(ViewSet):
    def retrieve(self, request, pk):
        """
        1.获取指定的订单信息
        2.将订单信息传给支付宝生成对应的支付页面
        3.拼接支付地址：网关 + 订单参数
        4.返回支付页面
        :param request:
        :param pk: 订单编号
        :return:
        """
        # 1.获取指定的订单信息
        try:
            order = Order.objects.get(order_id=pk, user=request.user, status=1)
        except Order.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        # 2.将订单信息传给支付宝生成对应的支付页面
        order_string = alipay.api_alipay_trade_page_pay(
            subject=f'LMS系统{order.order_id}',  # 订单标题
            out_trade_no=order.order_id,  # 订单编号
            total_amount=str(order.total_amount),
            return_url='http://localhost:8080/home/order/success',  # 回调地址
        )
        # 3.拼接支付地址：网关 + 订单参数
        pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string
        return Response({'pay_url': pay_url})

    def update(self, request):
        # 获取前端回调过来的数据(请求地址里）
        data = request.query_params.dict()

        try:
            sign = data.pop('sign')
        except KeyError:
            return Response(status=HTTP_400_BAD_REQUEST)

        # 校验
        res = alipay.verify(data, sign)
        if not res:
            return Response(status=HTTP_403_FORBIDDEN)

        # 取出订单编号和支付宝交易号
        order_id = data.get('out_trade_no')
        trade_no = data.get('trade_no')
        Payment.objects.create(order_id=order_id, trade_id=trade_no)
        Order.objects.filter(order_id=order_id, status=1).update(status=2)
        return Response({'order_id': order_id, 'trade_id': trade_no})
